unit fScenenav;

interface

uses
  System.SysUtils,
  System.Classes,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.ComCtrls,
  Vcl.ExtCtrls,
  Vcl.StdCtrls,

  GLS.SceneViewer,
  GLS.PersistentClasses,

  GLS.Scene,
  GLS.Context,
  GLS.State,
  GLS.Objects,
  GLS.GeomObjects,
  GLS.Cadencer,
  GLS.Extrusion,
  GLS.VectorGeometry,
  GLS.VectorTypes,
  GLS.GeometryBB,
  GLS.File3DS,
  GLS.VectorFileObjects,
  GLS.Coordinates,
  GLS.BaseClasses,
  GLS.RenderContextInfo,
  GLS.AsyncTimer,
  u_Frame,

  GLS.SimpleNavigation;

type
  TForm1 = class(TForm)
    Scene: TGLScene;
    vp: TGLSceneViewer;
    PanelLeft: TPanel;
    TreeView: TTreeView;
    Splitter1: TSplitter;
    Camera: TGLCamera;
    dcSpace: TGLDummyCube;
    dc_models: TGLDummyCube;
    dcCamera: TGLDummyCube;
    light: TGLLightSource;
    Cadencer: TGLCadencer;
    GLCube1: TGLCube;
    Frustrum: TGLFrustrum;
    _barrel: TGLRevolutionSolid;
    spBall: TGLSphere;
    sys_dogl: TGLDirectOpenGL;
    dcScene: TGLDummyCube;
    axis_lines: TGLLines;
    bb_lines: TGLLines;
    GLCube2: TGLCube;
    Cube: TGLCube;
    ffColumn: TGLFreeForm;
    frame: TFrame1;
    MemoInfo: TMemo;
    AsyncTimer: TGLAsyncTimer;
    Disk: TGLDisk;
    Cone: TGLCone;
    Cylinder: TGLCylinder;
    Torus: TGLTorus;
    procedure CadencerProgress(Sender: TObject;
      const deltaTime, newTime: Double);
    procedure FormCreate(Sender: TObject);
    procedure sys_doglRender(Sender: TObject; var rci: TGLRenderContextInfo);
    procedure vpMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure AsyncTimerTimer(Sender: TObject);
    procedure TreeViewDblClick(Sender: TObject);
    procedure TreeViewChange(Sender: TObject; Node: TTreeNode);
  public
    Pick: TGLBaseSceneObject;
    procedure UpdateTreeView;
    procedure AddBBox;
    procedure UpdateBBox;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// FormCreate
//
procedure TForm1.FormCreate;
begin
  vp.Buffer.RenderingContext.Activate;
  UpdateTreeView;
  ffColumn.LoadFromFile('column.3ds');
  ffColumn.Scale.Scale(1.5 / ffColumn.BoundingSphereRadius);
  TreeView.FullExpand;
end;

// cadProgress
//
procedure TForm1.CadencerProgress;
begin
  dcScene.Turn(deltaTime * 10);
  Cube.Roll(75 * deltaTime * sin(newTime));
  Cube.Turn(deltaTime * 50);
  spBall.Turn(deltaTime * 25);
  Disk.Turn(deltaTime * 100);
end;

// tvChange
//
procedure TForm1.TreeViewChange(Sender: TObject; Node: TTreeNode);
begin
  pick := TGLBaseSceneObject(Node.Data);
  MemoInfo.Text := pick.name + ': ' + pick.classname;
  frame.ShowParams;
end;

procedure TForm1.TreeViewDblClick(Sender: TObject);
begin
end;

// vpMouseDown
//
procedure TForm1.vpMouseDown;
var
  newpick: TGLBaseSceneObject;

begin
  newpick := vp.Buffer.GetPickedObject(X, Y);
  if newpick is TGLLines then
    exit;

  if newpick = nil then
    TreeView.Select(TreeView.Items[0])
  else
    TreeView.Select(TTreeNode(newpick.TagObject));
end;

// UpdateTreeView
//
procedure TForm1.UpdateTreeView;

  procedure GetObject(ParentNode: TTreeNode; Obj: TGLBaseSceneObject);
  var
    a1: Integer;
    Node: TTreeNode;
  begin
    Node := TreeView.Items.AddChildObject(ParentNode, obj.name, obj);
    Obj.TagObject := Node;
    for a1 := 0 to Obj.Count - 1 do
      GetObject(Node, Obj.Children[a1]);
  end;

begin
  TreeView.Items.Clear;
  GetObject(TreeView.TopItem, dcScene);
end;

// UpdateBBox
//
procedure TForm1.UpdateBBox;
var
  v1, v2: TVector3f;

begin
  if pick = nil then
    exit;
  if bb_lines.Nodes.Count = 0 then
    AddBBox;

  bb_lines.Matrix^ := pick.AbsoluteMatrix;
  if pick is TGLFreeForm then
    with TGLFreeForm(pick) do
    begin
      MeshObjects.GetExtents(v1, v2);
      v1 := VectorTransform(v1, pick.Matrix^);
      v2 := VectorTransform(v2, pick.Matrix^);
      bb_lines.Position.SetPoint(vectorlerp(v1, v2, 0.5));
      bb_lines.Scale.SetVector(pick.BoundingBox(false).BBox[0]);
      bb_lines.Scale.Scale(2);
    end
  else
  begin
    bb_lines.Scale.SetVector(pick.BoundingBox(false).BBox[0]);
    bb_lines.Scale.Scale(2.1);
  end;

  axis_lines.Matrix^ := pick.AbsoluteMatrix;
end;

// AddBBox
//
procedure TForm1.AddBBox;
const
  c = 0.5;
  d = 0.3;

begin
  with bb_lines.Nodes do
  begin
    AddNode(c, c, c);
    AddNode(c, c, d);
    AddNode(c, c, -c);
    AddNode(c, c, -d);
    AddNode(-c, c, c);
    AddNode(-c, c, d);
    AddNode(-c, c, -c);
    AddNode(-c, c, -d);
    AddNode(c, -c, c);
    AddNode(c, -c, d);
    AddNode(c, -c, -c);
    AddNode(c, -c, -d);
    AddNode(-c, -c, c);
    AddNode(-c, -c, d);
    AddNode(-c, -c, -c);
    AddNode(-c, -c, -d);

    AddNode(c, c, c);
    AddNode(c, d, c);
    AddNode(c, -c, c);
    AddNode(c, -d, c);
    AddNode(-c, c, c);
    AddNode(-c, d, c);
    AddNode(-c, -c, c);
    AddNode(-c, -d, c);
    AddNode(c, c, -c);
    AddNode(c, d, -c);
    AddNode(c, -c, -c);
    AddNode(c, -d, -c);
    AddNode(-c, c, -c);
    AddNode(-c, d, -c);
    AddNode(-c, -c, -c);
    AddNode(-c, -d, -c);

    AddNode(c, c, c);
    AddNode(d, c, c);
    AddNode(-c, c, c);
    AddNode(-d, c, c);
    AddNode(c, -c, c);
    AddNode(d, -c, c);
    AddNode(-c, -c, c);
    AddNode(-d, -c, c);
    AddNode(c, c, -c);
    AddNode(d, c, -c);
    AddNode(-c, c, -c);
    AddNode(-d, c, -c);
    AddNode(c, -c, -c);
    AddNode(d, -c, -c);
    AddNode(-c, -c, -c);
    AddNode(-d, -c, -c);
  end;
end;

// sys_doglRender
//
procedure TForm1.sys_doglRender;
begin
  if pick <> nil then
  begin
    rci.GLStates.DepthFunc := cfAlways;
    UpdateBBox;
    axis_lines.Render(rci);
    bb_lines.Render(rci);
  end;
end;

// atTimer
//
procedure TForm1.AsyncTimerTimer;
begin
  Caption := 'SceneNavigator / ' + vp.FramesPerSecondText(2);
  vp.ResetPerformanceMonitor;
end;

end.
